﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using MTDebug;
using nl.tno.ict.multitouch.wpfmultitouch.events;
using TouchLibEvents;
using System.ComponentModel;
using System.Windows.Input;
using System.Timers;



namespace nl.tno.ict.multitouch.wpfmultitouch.controls
{
    public class MTCanvas3D : Canvas, MTObject, INotifyPropertyChanged
    {
        private Ellipse _elRight;
        private bool _leftFingerdown;
        private bool _leftButtonDown;
        private long _leftFingerID;
        private bool _rightButtonDown;
        private bool _rightFingerdown;
        private long _rightFingerID;

        private long _fingerID;
        private UCDebugInfo _debuginfo;
        public event TuioMoveFingerHandler SimulatedFingerMoved;
        public event TuioRemoveFingerHandler SimulatedFingerRemoved;
        public event TuioNewFingerHandler SimulatedFingerNew;
        private int _clickCount = 0;

        public static readonly RoutedEvent ClickEvent;
        public static readonly RoutedEvent MouseDoubleClickEvent;
        private static List<MTCanvas3D> instances = new List<MTCanvas3D>();

        public static List<MTCanvas3D> Instances
        {
            get { return MTCanvas3D.instances; }
        }

        private int _timeout = 1000;
        public event NotMovedEventArgs NotMoved;
        private int _fingerCount;

        public bool _showFingerPos = false;
        // 2D
        Canvas menu;

        public Canvas Menu
        {
            get { return menu; }
        }
        // 3D
        public Viewport3D vp;

        Transform3DGroup translateGroup;
        public enum Navagations
        {
            Top,
            Bottom,
            Left,
            Right,
            Front,
            Back,
            Earthbound,
            Free
        }
        public Navagations SelectedView = Navagations.Free;
        private int flyToSteps = 20;
        private int flyToStepsCount = 0;
        public double camRoll = 0;
        public double camPitch = 0;
        public double camYaw = 0;
        public double camFly = 0;
        public double camPanHorizontal = 0;
        public double camPanVertical = 0;
        public double flySpeed = 0;
        public double camRollSpeed = 0;
        public double speed = 0;
        double r1 = 0;
        double r2 = 0;
        double r3 = 0;
        private Point3D flyToTemp = new Point3D();
        public Point3D maxXYZ = new Point3D(4000, 8000, 4000);
        public Point3D minXYZ = new Point3D(-4000, -1000, -4000);
        PerspectiveCamera pCam = new PerspectiveCamera(new Point3D(0, 0, 0), new Vector3D(0, -1, 0), new Vector3D(0, 0, -1), 45);
        Point3D p = new Point3D(0, 6000, 0);
        public Point3D surfaceTarget = new Point3D();
        private Model3DGroup mainGroup3D = new Model3DGroup();
        private List<ChildParentObject> childParents = new List<ChildParentObject>();

        public Model3DGroup MainGroup3D
        {
            get { return mainGroup3D; }
        }

        // Timer
        delegate void VoidDelegate();


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion



        #region region propertys

        private bool _debugEnabled = false;
        /// <summary>
        /// Set the debug property. 
        /// If true, a debuginfoscreen appears in the right corner 
        /// of the screen.
        /// </summary>
        public bool DebugEnabled
        {
            get
            {
                return _debugEnabled;
            }
            set
            {
                _debugEnabled = value;
                if (_debugEnabled)
                    this.showDebugInfo();
            }
        }
        private bool _simulationEnabled = false;
        /// <summary>
        /// Set the simulation property.
        /// If true, input (single point) with the mouse is possible.
        /// </summary>
        public bool SimulationEnabled
        {
            get
            {
                return _simulationEnabled;
            }
            set
            {
                _simulationEnabled = value;
                if (_simulationEnabled)
                    this.simulateInput();
            }
        }

        private bool _gesturesEnabled = true;
        /// <summary>
        /// Gets or sets a value if the gestures on the MTCanvas must be recognised.
        /// </summary>
        public bool GesturesEnabled { get { return _gesturesEnabled; } set { _gesturesEnabled = value; } }

        #endregion


        #region MTObject Members

        public bool CanBeScaled { get { return MTProperties.GetCanBeScaled(this); } set { MTProperties.SetCanBeScaled(this, value); } }
        public bool CanBeDragged { get { return MTProperties.GetCanBeDragged(this); } set { MTProperties.SetCanBeDragged(this, value); } }
        public bool CanBeClicked { get { return MTProperties.GetCanBeClicked(this); } set { MTProperties.SetCanBeClicked(this, value); } }
        public bool CanBeRotated { get { return MTProperties.GetCanBeRotated(this); } set { MTProperties.SetCanBeRotated(this, value); } }
        /// <summary>
        /// Gets or sets a bool that describes the value of a AdornersEnabledProperty for the element.
        /// </summary>
        public bool AdornersEnabled { get { return MTProperties.GetAdornersEnabled(this); } set { MTProperties.SetAdornersEnabled(this, value); } }

          #endregion

        /// <summary>
        /// The most important of the multitouch application. MTCanvas receives the multitouch events
        /// without a multitouch canvas your application wont work
        /// </summary>
        public MTCanvas3D()
        {
            // Sets the TouchEnabledObjectProperty for the element always true.
            instances.Add(this);


            vp = new Viewport3D();
            menu = new Canvas();


            MTProperties.SetTouchEnabled(this, true);

            Timer CameraTimer = new Timer();
            CameraTimer.Elapsed += new ElapsedEventHandler(CameraTimer_Elapsed);
            CameraTimer.Start();

            translateGroup = new Transform3DGroup();



            _fingerID = 0;
            this.Loaded += new RoutedEventHandler(MTCanvas_Loaded);
            this.Background = new SolidColorBrush(Colors.White);//With a transparant background the simulation has a error.. (TODO)
            this.Click += new RoutedEventHandler(MTCanvas_Click);

        }

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            if (vp != null)
            {
                SyncVPSize();
            }
        }
        public void SyncVPSize()
        {
            vp.Width = this.ActualWidth;
            vp.Height = this.ActualHeight;
            menu.Width = this.ActualWidth;
            menu.Height = this.ActualHeight;
        }


        void CameraTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new VoidDelegate(delegate
            {
                TimerEvent();
            }));
        }
        private void TimerEvent()
        {
            //this.Camera = persCam;
            PerspectiveCamera cam = (PerspectiveCamera)pCam;

            Double grad = (Double)(180 / (Double)Math.PI);
            Double rad = (Double)(Math.PI / (Double)180);

            Transform3DGroup htrans = new Transform3DGroup();
            htrans.Children.Add(new ScaleTransform3D(100, 100, 100));
            htrans.Children.Add(translateGroup);
            //mHitPlane.Transform = htrans;

            cam.Transform = translateGroup;
            translateGroup.Children.Clear();
            Transform3DGroup yaw = new Transform3DGroup();
            Transform3DGroup pitch = new Transform3DGroup();
            Transform3DGroup roll = new Transform3DGroup();
            pitch.Children.Add(roll);
            yaw.Children.Add(pitch);
            translateGroup.Children.Add(yaw);


            Point3D pTemp = p;

            if (flyToStepsCount == 0)
            {
                if (speed > 0)
                {
                    camPitch = camPitch / speed;
                    camYaw = camYaw / speed;
                    camRollSpeed = camRollSpeed / speed;

                }
                if (flySpeed > 0)
                {
                    camFly = camFly / flySpeed;
                    camPanVertical = camPanVertical / flySpeed;
                    camPanHorizontal = camPanHorizontal / flySpeed;
                }

                switch (SelectedView)
                {
                    case Navagations.Top:
                        //r1 += camRoll;
                        camRoll += camRollSpeed;
                        r2 = 90;
                        r3 = 0;
                        double a1 = Math.Atan2(camPanVertical, camPanHorizontal);

                        double d2 = Math.Sqrt(Math.Pow(camPanHorizontal, 2) + Math.Pow(camPanVertical, 2));// camPanHorizontal / Math.Sin(a1);

                        double x = (d2 * Math.Cos((-camRoll * rad) + a1));
                        double y = camFly;
                        double z = (d2 * Math.Sin((-camRoll * rad) + a1));

                        pTemp.Offset(x, y, z);

                        break;
                    case Navagations.Bottom:
                        r2 = -90;
                        r3 = 0;
                        break;
                    case Navagations.Front:
                        r2 = 0;
                        r3 = 90;
                        break;
                    case Navagations.Back:
                        r2 = 0;
                        r3 = -90;
                        break;
                    case Navagations.Left:
                        r2 = 0;
                        r3 = 180;
                        break;
                    case Navagations.Right:
                        r2 = 0;
                        r3 = 0;
                        break;
                    case Navagations.Earthbound:

                        //surfaceTarget = new Point3D((Math.Sin(r3 * rad) * (p.Y / Math.Tan(r2 * rad))), 0, (Math.Cos(r3 * rad) * (p.Y / Math.Tan(r2 * rad))));
                        //mCube.Transform = new TranslateTransform3D(surfaceTarget.X + p.X, surfaceTarget.Y, surfaceTarget.Z + p.Z);
                        break;
                    case Navagations.Free:


                        r2 -= camPitch;
                        r3 += camYaw;


                        double d = Math.Sqrt(Math.Pow(Math.Sin(r3 * rad), 2) + Math.Pow(Math.Cos(r3 * rad), 2));
                        pTemp.Offset(Math.Sin(r3 * rad) * (camFly), (Math.Tan(-r2 * rad) * d) * (camFly), Math.Cos(r3 * rad) * (camFly));

                        double dh = Math.Sqrt(Math.Pow(Math.Sin((r3 - 90) * rad), 2) + Math.Pow(Math.Cos((r3 - 90) * rad), 2));
                        pTemp.Offset(Math.Sin((r3 - 90) * rad) * (camPanHorizontal), (Math.Tan(-r2 * rad) * dh) * (camPanHorizontal), Math.Cos((r3 - 90) * rad) * (camPanHorizontal));



                        //surfaceTarget = new Point3D((Math.Sin(r3 * rad) * (p.Y / Math.Tan(r2 * rad))), 0, (Math.Cos(r3 * rad) * (p.Y / Math.Tan(r2 * rad))));
                        break;
                }

            }
            else
            {

                double u1 = (Convert.ToDouble(flyToStepsCount) / flyToSteps);
                double u2 = (Convert.ToDouble(flyToStepsCount - 1) / flyToSteps);
                double m1 = Math.Sin((Math.PI / 2) * u1);
                double m2 = Math.Sin((Math.PI / 2) * u2);
                pTemp.X += (flyToTemp.X * m1) - (flyToTemp.X * m2);
                //p.Y += (flyToTemp.Y /= 1.3);
                pTemp.Z += (flyToTemp.Z * m1) - (flyToTemp.Z * m2);


                if (flyToStepsCount >= flyToSteps)
                {
                    flyToStepsCount = 0;
                }
                else
                {
                    flyToStepsCount++;
                }

            }






            //pTemp.Y = p.Y + (Math.Tan(-r2 * rad) * d) * (camFly);
            //p.Y += (Math.Tan(-r2 * rad) * d) * (camFly);

            //cam.LookDirection = new Vector3D(0, 0, -1);
            yaw.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), r3)));
            pitch.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), r2)));
            roll.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), -camRoll)));


            if (pTemp.X > minXYZ.X && pTemp.X < maxXYZ.X)
            {
                p.X = pTemp.X;
            }
            if (pTemp.Y > minXYZ.Y && pTemp.Y < maxXYZ.Y)
            {
                p.Y = pTemp.Y;
            }
            if (pTemp.Z > minXYZ.Z && pTemp.Z < maxXYZ.Z)
            {
                p.Z = pTemp.Z;
            }
            translateGroup.Children.Add(new TranslateTransform3D(p.X, p.Y, p.Z));

            surfaceTarget = new Point3D((Math.Sin(r3 * rad) * (p.Y / Math.Tan(r2 * rad))), 0, (Math.Cos(r3 * rad) * (p.Y / Math.Tan(r2 * rad))));


        }


        void MTCanvas_Click(object sender, RoutedEventArgs e)
        {
        }

        public event RoutedEventHandler MouseDoubleClick
        {
            add { AddHandler(MTButton.MouseDoubleClickEvent, value); }
            remove { RemoveHandler(MTButton.MouseDoubleClickEvent, value); }
        }

        void MTCanvas_PreviewClick(object sender, RoutedEventArgs e)
        {
        }
        public bool GeometryModel3DExist(Object o)
        {
            foreach (ChildParentObject cpo in childParents)
            {
                if (cpo.Child.GetHashCode() == o.GetHashCode())
                    return true;
            }
            return false;
        }

        static MTCanvas3D()
        {


            MTCanvas3D.ClickEvent = EventManager.RegisterRoutedEvent("ClickEvent",
            RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(MTCanvas3D));

            MTCanvas3D.MouseDoubleClickEvent = EventManager.RegisterRoutedEvent("CanvasMouseDoubleClickEvent",
            RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(MTCanvas3D));

        }

        public static List<Object> Get3DStack(Object o)
        {
            foreach (MTCanvas3D mtc in instances)
            {
                if (mtc.GeometryModel3DExist(o))
                {
                    return mtc.GetStack(o);
                }
            }
            return null;
        }
        public static MTCanvas3D GetModel3DParent(Object o)
        {
            foreach (MTCanvas3D mtc in instances)
            {
                if (mtc.GeometryModel3DExist(o))
                {
                    return mtc;
                }
            }
            return null;
        }
        public event RoutedEventHandler Click
        {
            add { AddHandler(MTButton.ClickEvent, value); }
            remove { RemoveHandler(MTButton.ClickEvent, value); }
        }

        void MTCanvas_Loaded(object sender, RoutedEventArgs e)
        {






            /*if (SimulatedFingerMoved != null)
            {
                SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         position = new Point(58, 44),
                         Id = _fingerID
                     }));
            }
            _fingerID++;
            */



            vp.Width = 100;
            vp.Height = 100;
            pCam.FarPlaneDistance = 100000;
            vp.Camera = pCam;//new PerspectiveCamera(new Point3D(0, 300, 0), ;
            this.Children.Add(vp);
            this.Children.Add(menu);

            Window w = Window.GetWindow(this);

            //Material rood = (Material)w.FindResource("rood");
            //Geometry3D cube = (Geometry3D)w.FindResource("cube");
            //GeometryModel3D mCube = new GeometryModel3D(cube, rood);
            //mainGroup3D.Children.Add(mCube);
            ModelVisual3D v3d = new ModelVisual3D();

            v3d.Content = mainGroup3D;
            vp.Children.Add(v3d);

            MTSlider mtslider = new MTSlider();
            mtslider.Orientation = Orientation.Vertical;
            mtslider.Height = 100;

            mtslider.Loaded += new RoutedEventHandler(mtslider_Loaded);
            menu.Children.Add(mtslider);
            //menu.Visibility = Visibility.Collapsed;

            ModelVisual3D lights = new ModelVisual3D();
            lights.Content = new DirectionalLight(Colors.White, new Vector3D(0, -1, -1));
            vp.Children.Add(lights);

            SyncVPSize();

            setChildParentTable();



        }

        void mtslider_Loaded(object sender, RoutedEventArgs e)
        {
            MTSlider slider = sender as MTSlider;
            //slider.Visibility = Visibility.Collapsed;
        }

        //public bool GestureModuleEnabled { get { return _gesturModuleEnabled; } set { GestureModuleEnabled = value; } }
        public List<Object> GetStack(Object o)
        {
            List<Object> l = new List<object>();
            while (o != null)
            {
                l.Add(o);
                o = getParent3D(o);
            }
            l.Add(this);
            return l;
        }
        private Object getParent3D(Object o)
        {
            foreach (ChildParentObject cpo in childParents)
            {
                if (o.GetHashCode() == cpo.Child.GetHashCode())
                {
                    return cpo.Parent;
                }
            }
            return null;
        }
        private void setChildParentTable()
        {
            foreach (ModelVisual3D mv3d in vp.Children)
            {
                Console.WriteLine("main Visual3D");
                getVisualChildren(mv3d);
                childParents.Add(new ChildParentObject(mv3d, vp));
            }
        }
        private void getVisualChildren(ModelVisual3D mv3d)
        {
            if (mv3d.Content is Model3DGroup)
            {
                Console.WriteLine("main Model3DGroup");
                getModelGroupChildren((Model3DGroup)mv3d.Content);
                childParents.Add(new ChildParentObject(mv3d.Content, mv3d));
            }
            foreach (ModelVisual3D v3d in mv3d.Children)
            {
                Console.WriteLine("sub Visual3D");
                getVisualChildren(v3d);
                childParents.Add(new ChildParentObject(v3d, mv3d));
            }
        }
        private void getModelGroupChildren(Model3DGroup m3dg)
        {

            foreach (Model3D m3d in m3dg.Children)
            {
                if (m3d is Model3DGroup)
                {
                    Console.WriteLine("sub Model3DGroup");
                    getModelGroupChildren((Model3DGroup)m3d);

                }
                else if (m3d is GeometryModel3D)
                {
                    Console.WriteLine("GeometryModel3D   x:" + m3d.Bounds.Size.X.ToString() + ", y:" + m3d.Bounds.Size.Y.ToString() + ", z" + m3d.Bounds.Size.Z.ToString());


                }
                childParents.Add(new ChildParentObject(m3d, m3dg));
            }
        }

        public bool IsDragging
        {
            get { return MTProperties.GetIsDragging(this); }
            set { MTProperties.SetIsDragging(this, value); }

        }

        public bool IsScaling
        {
            get { return MTProperties.GetIsScaling(this); }
            set
            {
                MTProperties.SetIsScaling(this, value);
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsScaling"));
            }
        }

        public bool IsRotating
        {
            get { return MTProperties.GetIsRotating(this); }
            set { MTProperties.SetIsRotating(this, value); }
        }

        /// <summary>
        /// If debug property is true, the debug info screen will always appear in the upper right corner of 
        /// the screen. 
        /// </summary>
        public void PositioningDebugInfo()
        {
            if (_debuginfo != null)
            {
                Canvas.SetTop(_debuginfo, 0);
                Canvas.SetLeft(_debuginfo, this.ActualWidth - _debuginfo.ActualWidth);
            }
        }

        /// <summary>
        /// If the simulate input property is true, the simulateInput will be used to catch the mouse events and
        /// draw a small ellipse under the mouse pointer
        /// </summary>
        private void simulateInput()
        {
            _elRight = new Ellipse();
            _elRight.Height = 10;
            _elRight.Width = 10;
            _elRight.Fill = new SolidColorBrush(Colors.Black);
            _elRight.IsHitTestVisible = false;
            Canvas.SetZIndex(_elRight, 20);

            this.PreviewMouseMove += new System.Windows.Input.MouseEventHandler(MTCanvas_PreviewMouseMove); //new System.Windows.Input.MouseEventHandler(MTCanvas_MouseMove);
            //this.MouseMove += new System.Windows.Input.MouseEventHandler(MTCanvas_MouseMove);
            this.PreviewMouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseLeftButtonDown); //+= new System.Windows.Input.MouseButtonEventHandler(MTCanvas_MouseLeftButtonDown);
            this.PreviewMouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseLeftButtonUp); //+= new System.Windows.Input.MouseButtonEventHandler(MTCanvas_MouseLeftButtonUp);
            this.PreviewMouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseRightButtonDown);
            this.PreviewMouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseRightButtonUp);
        }

        internal void MTCanvas_PreviewMouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Canvas.SetZIndex(_elRight, 26);
            _rightButtonDown = false;
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _rightButtonDown = true;
            if (!_rightFingerdown)
            {
                _fingerID++;
                _rightFingerID = _fingerID;

                this.Children.Add(_elRight);
                Canvas.SetTop(_elRight, e.GetPosition(this).Y);
                Canvas.SetLeft(_elRight, e.GetPosition(this).X);
                Canvas.SetZIndex(_elRight, -10);
                _rightFingerdown = true;
                if (SimulatedFingerNew != null)
                {
                    SimulatedFingerNew(sender, new TuioNewFingerEventArgs(_fingerID));
                }

                if (SimulatedFingerMoved != null)
                {
                    SimulatedFingerMoved(sender,
                         new TuioMoveFingerEventArgs(new FingerObject()
                         {
                             CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                             Id = _fingerID
                         }));
                }
            }
            else
            {
                _rightFingerdown = false;
                if (SimulatedFingerMoved != null)
                {
                    Canvas.SetZIndex(_elRight, 1);
                    SimulatedFingerRemoved(sender, new TuioRemoveFingerEventArgs(_rightFingerID));
                }
                this.Children.Remove(_elRight);
            }
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _leftButtonDown = false;
            if (SimulatedFingerRemoved != null)
            {
                SimulatedFingerRemoved(sender, new TuioRemoveFingerEventArgs(_leftFingerID));
            }
        }

        internal void MTCanvas_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //Console.WriteLine(e.GetPosition(this).X + " " + e.GetPosition(this).Y);

            _leftButtonDown = true;
            _fingerID++;
            _leftFingerID = _fingerID;
            if (SimulatedFingerNew != null)
            {
                SimulatedFingerNew(sender, new TuioNewFingerEventArgs(_fingerID));
            }

            if (SimulatedFingerMoved != null)
            {
                SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
            }
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (SimulationEnabled)
            {
                if (_leftButtonDown && SimulatedFingerMoved != null)
                {
                    SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
                }

                if (_rightButtonDown && _rightFingerdown && SimulatedFingerMoved != null)
                {
                    Canvas.SetTop(_elRight, e.GetPosition(this).Y);
                    Canvas.SetLeft(_elRight, e.GetPosition(this).X);

                    SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
                }
            }
            e.Handled = true;
        }

        /// <summary>
        /// If the showdebuginfo property is true, this method will be used to make a new instance of de UCDebugInfo(usercontrol)
        /// Use the method "Write" to write output to the screen.
        /// </summary>
        private void showDebugInfo()
        {
            //add UCDebugInfo screen here;
            _debuginfo = new UCDebugInfo();
            this.Children.Add(_debuginfo);
            // _processing.newDebugInfo += new DebugInfoHandler(_processing_newDebugInfo);

        }

        /// <summary>
        /// If the Debug property is true, this method can be used to write output to the 
        /// debug info screen in the upper right corner of the canvas
        /// </summary>
        /// <param name="output">The input string</param>
        public void Write(string input)
        {
            if (_debugEnabled)
                _debuginfo.OutputWrite(input);
        }

        /// <summary>
        /// Set the amount of fingers in the debug info screen in the upper right corner of the canvas
        /// </summary>
        /// <param name="fingercount"></param>
        public void SetFingerCount(int fingercount)
        {
            if (_debugEnabled)
                _debuginfo.SetFingerCount(fingercount);
        }

        /// <summary>
        /// Get the left count of pixels from the desktop to window
        /// </summary>
        /// <returns>Amount of left pixels</returns>
        public double Left()
        {
            if (Parent is Window) return ((Window)Parent).Left;
            return 0.0;
        }

        /// <summary>
        /// Get the top count of pixels from the desktop to window
        /// </summary>
        /// <returns>Amount of left pixels</returns>
        public double Top()
        {
            if (Parent is Window) return ((Window)Parent).Top;
            return 0.0;
        }

        /// <summary>
        /// Close the nl.tno.ict.multitouch.framework.tuio listener thread
        /// </summary>
        public void Disconnect()
        {
            //_processing.Disconnect();
        }

        /// <summary>
        /// Gets or sets the timeout, in ms, used to by the NotMoved event. Default: 1000 ms
        /// </summary>s
        int MTObject.Timeout
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        #region MTObject Members

        public int FingerCount
        {
            get
            {
                return _fingerCount;
            }
            set
            {
                _fingerCount = value;
            }
        }
        /// <summary>
        /// Gets or sets the onTop dependency property. When true, when a finger touches the object the object
        /// gets on top of the screen (z-index changes).
        /// </summary>
        public bool OnTop
        {
            get { return MTProperties.GetOnTop(this); }
            set { MTProperties.SetOnTop(this, value); }
        }


        void MTObject.NotMoved()
        {
            if (NotMoved != null)
                NotMoved(this, new EventArgs());
        }

        /// <summary>
        /// Set the object TouchEnabled. When an object isn't touchEnabled interaction with fingers is not
        /// possible (nothing will happen).
        /// </summary>
        public bool TouchEnabled
        {
            get { return MTProperties.GetTouchEnabled(this); }
            set { MTProperties.SetTouchEnabled(this, value); }
        }

        #endregion
    }
    class ChildParentObject
    {
        private Object child;

        public Object Child
        {
            get { return child; }
        }
        private Object parent;

        public Object Parent
        {
            get { return parent; }
        }
        public ChildParentObject(Object _child, Object _parent)
        {
            child = _child;
            parent = _parent;
        }
    }
}
